iT邦幫忙

2024 iThome 鐵人賽

DAY 10
0
自我挑戰組

自學vue~點亮Roadmap過程系列 第 10

vue3鍊成術第十天-計算屬性(實作)

  • 分享至 

  • xImage
  •  

計算屬性

讓我們在上一步的 todo 列表基礎上繼續。現在,我們已經給每一個 todo 添加了切換功能。這是通過給每一個 todo 對象添加 done 屬性來實現的,並且使用了 v-model 將其綁定到複選框上:

<li v-for="todo in todos">
  <input type="checkbox" v-model="todo.done">
  ...
</li>

下一個可以添加的改進是隱藏已經完成的 todo。我們已經有了一個能夠切換 hideCompleted 狀態的按鈕。但是應該如何基於狀態渲染不同的列表項呢?

介紹一個新 API:computed()。它可以讓我們創建一個計算屬性 ref,這個 ref 會動態地根據其他響應式數據源來計算其 .value:

import { ref, computed } from 'vue'

const hideCompleted = ref(false)
const todos = ref([
  /* ... */
])

const filteredTodos = computed(() => {
  // 根據 `todos.value` & `hideCompleted.value`
  // 返回過濾後的 todo 項目
})

計算屬性會自動跟蹤其計算中所使用的到的其他響應式狀態,並將它們收集為自己的依賴。計算結果會被緩存,並只有在其依賴發生改變時才會被自動更新。

實作

試著添加 filteredTodos 計算屬性並實現計算邏輯!如果實現正確,在隱藏已完成項目的狀態下勾選一個 todo,它也應當被立即隱藏。

<script setup>
import { ref } from 'vue'

let id = 0

const newTodo = ref('')
const hideCompleted = ref(false)
const todos = ref([
  { id: id++, text: 'Learn HTML', done: true },
  { id: id++, text: 'Learn JavaScript', done: true },
  { id: id++, text: 'Learn Vue', done: false }
])

function addTodo() {
  todos.value.push({ id: id++, text: newTodo.value, done: false })
  newTodo.value = ''
}

function removeTodo(todo) {
  todos.value = todos.value.filter((t) => t !== todo)
}
</script>

<template>
  <form @submit.prevent="addTodo">
    <input v-model="newTodo" required placeholder="new todo">
    <button>Add Todo</button>
  </form>
  <ul>
    <li v-for="todo in todos" :key="todo.id">
      <input type="checkbox" v-model="todo.done">
      <span :class="{ done: todo.done }">{{ todo.text }}</span>
      <button @click="removeTodo(todo)">X</button>
    </li>
  </ul>
  <button @click="hideCompleted = !hideCompleted">
    {{ hideCompleted ? 'Show all' : 'Hide completed' }}
  </button>
</template>

<style>
.done {
  text-decoration: line-through;
}
</style>

完成

filteredTodos: 根據 hideCompleted 的值,返回過濾後的待辦事項列表。如果 hideCompleted 為 true,則只返回未完成的待辦事項。

<script setup>
import { ref, computed } from 'vue'

let id = 0

const newTodo = ref('')
const hideCompleted = ref(false)
const todos = ref([
  { id: id++, text: 'Learn HTML', done: true },
  { id: id++, text: 'Learn JavaScript', done: true },
  { id: id++, text: 'Learn Vue', done: false }
])

const filteredTodos = computed(() => {
  return hideCompleted.value
    ? todos.value.filter((t) => !t.done)
    : todos.value
})

function addTodo() {
  todos.value.push({ id: id++, text: newTodo.value, done: false })
  newTodo.value = ''
}

function removeTodo(todo) {
  todos.value = todos.value.filter((t) => t !== todo)
}
</script>

<template>
  <form @submit.prevent="addTodo">
    <input v-model="newTodo" required placeholder="new todo">
    <button>Add Todo</button>
  </form>
  <ul>
    <li v-for="todo in filteredTodos" :key="todo.id">
      <input type="checkbox" v-model="todo.done">
      <span :class="{ done: todo.done }">{{ todo.text }}</span>
      <button @click="removeTodo(todo)">X</button>
    </li>
  </ul>
  <button @click="hideCompleted = !hideCompleted">
    {{ hideCompleted ? 'Show all' : 'Hide completed' }}
  </button>
</template>

<style>
.done {
  text-decoration: line-through;
}
</style>

https://ithelp.ithome.com.tw/upload/images/20240923/20169210fadTOdMSM8.pnghttps://ithelp.ithome.com.tw/upload/images/20240923/20169210D79FScIsAe.png


上一篇
vue3鍊成術第九天-列表渲染(實作)
下一篇
vue3鍊成術第十一天-生命週期和模板引用(實作)
系列文
自學vue~點亮Roadmap過程30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言